package service

import (
	"errors"
	"fmt"
	beego "github.com/beego/beego/v2/server/web"
	"ksd-social-api/commons/page"
	"ksd-social-api/commons/tools"
	"ksd-social-api/modules/common/pay/service"
	"ksd-social-api/modules/special/model"
	"ksd-social-api/modules/special/model/context"
	"ksd-social-api/modules/special/model/vo"
	"ksd-social-api/utils"
	"ksd-social-api/utils/rdb"
)

type SpecialService struct{}

var specialBindService = SpecialBindService{}
var userNoteService = service.UserNoteService{}

/**
 * @author feige
 * @date 2023-10-08
 * @desc 根据id查询资源信息，不包含内容
 */
func (service *SpecialService) GetSpecialByIDToPay(specialId uint64, systemId uint64) (pvo *vo.SpecialDetailPayVo, err error) {
	// 1: 根据id查询数据层
	special, err := specialMapper.GetByIdTOPay(specialId, systemId)
	if err != nil {
		return nil, err
	}
	specialDetailPayVo := vo.SpecialDetailPayVo{}
	utils.CopyProperties(&specialDetailPayVo, special)
	return &specialDetailPayVo, nil
}

/**
 * @author feige
 * @date 2023-10-08
 * @desc 根据id查询资源信息的业务蹭
 */
func (service *SpecialService) GetUserStudyDetailByPath(specialPath string, userId uint64, systemId uint64) (pvo *vo.SpecialDetailVo, err error) {
	cacheKey := fmt.Sprintf("SYSTEM:SPECIAL:GetUserStudyDetailByPath:%s:%d", specialPath, systemId)
	checkKey := rdb.RdbCheck(cacheKey)
	specialDetailVo := vo.SpecialDetailVo{}
	if checkKey {
		jsonString, _ := rdb.RdbGet(cacheKey)
		if len(jsonString) == 0 {
			return nil, errors.New("查无此资源")
		}
		tools.JsontoStruct(jsonString, &specialDetailVo)
	} else {
		// 1: 根据id查询数据层
		special, err := specialMapper.GetByPath(specialPath, systemId)
		if err != nil {
			rdb.RdbSetEX(cacheKey, "", 60*60*24)
			return nil, err
		}
		utils.CopyProperties(&specialDetailVo, special)
		// 获取评分
		specialDetailVo.Score = commentMapper.SumSocre(special.Id, systemId)
		if specialDetailVo.Score == 0 {
			specialDetailVo.Score = 5
		}
		// 绑定学生
		specialDetailVo.Students = service.FindSpecialStudents(special.Id, systemId)
		// 绑定明细
		specialDetailVo.BindList, _ = specialBindService.FindAdminSpecialBinds(specialDetailVo.Id, userId, systemId, false)
		rdb.RdbSetEX(cacheKey, tools.StructToJson(specialDetailVo), 60*60*24)
	}

	// 用户相关的操作和统计
	if userId > 0 {
		// 支付的小册金额
		specialDetailVo.SumPrice = userNoteService.SumUserByNote(specialDetailVo.Id, userId, systemId)
		// 绑定明细
		specialDetailVo.BindList, _ = specialBindService.FindAdminSpecialBinds(specialDetailVo.Id, userId, systemId, true)
		// 计算用户的总体进度
		specialDetailVo.StudySpecial = noteMapper.CountNoteSpecialStudysTotal(specialDetailVo.Id, userId, systemId)
		// 点赞
		//specialDetailVo.LikeFlag = specialUserLikeMapper.CountSpecialUserLike(userId, specialDetailVo.Id, systemId)
		// 收藏
		specialDetailVo.FavFlag = specialUserFavMapper.CountSpecialUserFav(userId, specialDetailVo.Id, systemId)
		// 判断用户是否购买资源
		specialDetailVo.BuyFlag, _ = service.ValidatorUserSpecial(&specialDetailVo, userId, specialDetailVo.Id, systemId)
		// 购买人数
		specialDetailVo.BuyNum = userBuySpecialMapper.CountUserBuySpecialNo(userId, specialDetailVo.Id, systemId)
		if specialDetailVo.BuyFlag <= 0 {
			specialDetailVo.PanPwd = ""
		}
	} else {
		// 清空密码
		specialDetailVo.PanPwd = ""
	}
	// 章绑定节
	return &specialDetailVo, err
}

/**
 * @author feige
 * @date 2023-10-08
 * @desc 根据id查询资源信息的业务蹭
 */
func (service *SpecialService) GetSpecialByPath(specialPath string, userId uint64, systemId uint64) (pvo *vo.SpecialDetailVo, err error) {
	cacheKey := fmt.Sprintf("SYSTEM:SPECIAL:GetSpecialByPath:%s:%d", specialPath, systemId)
	checkKey := rdb.RdbCheck(cacheKey)
	specialDetailVo := vo.SpecialDetailVo{}
	panPwd := ""
	if checkKey {
		jsonString, _ := rdb.RdbGet(cacheKey)
		if len(jsonString) == 0 {
			return nil, errors.New("查无此资源")
		}
		tools.JsontoStruct(jsonString, &specialDetailVo)
	} else {
		// 1: 根据id查询数据层
		special, err := specialMapper.GetByPath(specialPath, systemId)
		if err != nil {
			rdb.RdbSetEX(cacheKey, "", 60*60*24)
			return nil, err
		}
		utils.CopyProperties(&specialDetailVo, special)
		// 获取评分
		specialDetailVo.Score = commentMapper.SumSocre(special.Id, systemId)
		if specialDetailVo.Score == 0 {
			specialDetailVo.Score = 5
		}
		// 绑定明细
		specialDetailVo.BindList, _ = specialBindService.FindAdminSpecialBinds(special.Id, userId, systemId, false)
		// 绑定学生
		specialDetailVo.Students = service.FindSpecialStudents(special.Id, systemId)
	}
	// 用户相关的操作和统计
	if userId > 0 {
		// 支付的小册金额
		specialDetailVo.SumPrice = userNoteService.SumUserByNote(specialDetailVo.Id, userId, systemId)
		// 收藏
		specialDetailVo.FavFlag = specialUserFavMapper.CountSpecialUserFav(userId, specialDetailVo.Id, systemId)
		// 判断用户是否购买资源
		specialDetailVo.BuyFlag, _ = service.ValidatorUserSpecial(&specialDetailVo, userId, specialDetailVo.Id, systemId)
		// 购买人数
		specialDetailVo.BuyNum = userBuySpecialMapper.CountUserBuySpecialNo(userId, specialDetailVo.Id, systemId)

		if specialDetailVo.BuyFlag > 0 {
			// 如果网盘密码不为空就要进行加密
			if len(panPwd) > 0 {
				specialDetailVo.PanPwd = panPwd
			}
		}
		rdb.RdbSetEX(cacheKey, tools.StructToJson(specialDetailVo), 60*60*24)
	} else {
		// 清空密码
		specialDetailVo.PanPwd = ""
	}
	// 章绑定节
	return &specialDetailVo, err
}

/**
 * @author feige
 * @date 2023-10-08
 * @desc 根据id查询资源信息的业务蹭
 */
func (service *SpecialService) GetSpecialByID(specialId uint64, userId uint64, systemId uint64) (pvo *vo.SpecialDetailVo, err error) {
	cacheKey := fmt.Sprintf("SYSTEM:SPECIAL:GetSpecialByID:%d:%d", specialId, systemId)
	checkKey := rdb.RdbCheck(cacheKey)
	specialDetailVo := vo.SpecialDetailVo{}
	panPwd := ""
	if checkKey {
		jsonString, _ := rdb.RdbGet(cacheKey)
		if len(jsonString) == 0 {
			return nil, errors.New("查无此资源")
		}
		tools.JsontoStruct(jsonString, &specialDetailVo)
	} else {
		// 1: 根据id查询数据层
		special, err := specialMapper.GetById(specialId, systemId)
		if err != nil {
			rdb.RdbSetEX(cacheKey, "", 60*60*24)
			return nil, err
		}
		utils.CopyProperties(&specialDetailVo, special)
		panPwd = specialDetailVo.PanPwd
		// 清空密码
		specialDetailVo.PanPwd = ""
		// 获取评分
		specialDetailVo.Score = commentMapper.SumSocre(specialId, systemId)
		if specialDetailVo.Score == 0 {
			specialDetailVo.Score = 5
		}
		// 绑定明细
		specialDetailVo.BindList, _ = specialBindService.FindAdminSpecialBinds(specialId, userId, systemId, false)
		// 绑定学生
		specialDetailVo.Students = service.FindSpecialStudents(specialId, systemId)
	}
	// 用户相关的操作和统计
	if userId > 0 {
		// 关注
		//specialDetailVo.FocusFlag = userFocusMapper.CountUserFocus(userId, specialDetailVo.Userid, systemId)
		// 点赞
		//specialDetailVo.LikeFlag = specialUserLikeMapper.CountSpecialUserLike(userId, specialId, systemId)
		// 支付的小册金额
		specialDetailVo.SumPrice = userNoteService.SumUserByNote(specialDetailVo.Id, userId, systemId)
		// 收藏
		specialDetailVo.FavFlag = specialUserFavMapper.CountSpecialUserFav(userId, specialId, systemId)
		// 判断用户是否购买资源
		specialDetailVo.BuyFlag, _ = service.ValidatorUserSpecial(&specialDetailVo, userId, specialId, systemId)
		// 购买人数
		specialDetailVo.BuyNum = userBuySpecialMapper.CountUserBuySpecialNo(userId, specialId, systemId)

		if specialDetailVo.BuyFlag > 0 {
			// 如果网盘密码不为空就要进行加密
			if len(panPwd) > 0 {
				specialDetailVo.PanPwd = panPwd
			}
		}
		rdb.RdbSetEX(cacheKey, tools.StructToJson(specialDetailVo), 60*60*24)
	}
	// 章绑定节
	return &specialDetailVo, err
}

/**
 * @author feige
 * @date 2023-10-08
 * @desc 根据id查询资源信息的业务蹭
 */
func (service *SpecialService) GetUserStudyDetailById(specialId uint64, userId uint64, systemId uint64) (pvo *vo.SpecialDetailVo, err error) {
	cacheKey := fmt.Sprintf("SYSTEM:SPECIAL:GetUserStudyDetailById:%d:%d", specialId, systemId)
	checkKey := rdb.RdbCheck(cacheKey)
	specialDetailVo := vo.SpecialDetailVo{}
	panPwd := ""
	if checkKey {
		jsonString, _ := rdb.RdbGet(cacheKey)
		if len(jsonString) == 0 {
			return nil, errors.New("查无此资源")
		}
		tools.JsontoStruct(jsonString, &specialDetailVo)
	} else {
		// 1: 根据id查询数据层
		special, err := specialMapper.GetById(specialId, systemId)
		if err != nil {
			rdb.RdbSetEX(cacheKey, "", 60*60*24)
			return nil, err
		}
		utils.CopyProperties(&specialDetailVo, special)
		panPwd = specialDetailVo.PanPwd
		// 清空密码
		specialDetailVo.PanPwd = ""
		// 获取评分
		specialDetailVo.Score = commentMapper.SumSocre(specialId, systemId)
		if specialDetailVo.Score == 0 {
			specialDetailVo.Score = 5
		}
		// 绑定明细
		specialDetailVo.BindList, _ = specialBindService.FindAdminSpecialBinds(specialId, userId, systemId, true)
		// 绑定学生
		specialDetailVo.Students = service.FindSpecialStudents(specialId, systemId)
		rdb.RdbSetEX(cacheKey, tools.StructToJson(specialDetailVo), 60*60*24)
	}
	// 用户相关的操作和统计
	if userId > 0 {
		// 支付的小册金额
		specialDetailVo.SumPrice = userNoteService.SumUserByNote(specialDetailVo.Id, userId, systemId)
		// 计算用户的总体进度
		specialDetailVo.StudySpecial = noteMapper.CountNoteSpecialStudysTotal(specialId, userId, systemId)
		// 关注
		//specialDetailVo.FocusFlag = userFocusMapper.CountUserFocus(userId, specialDetailVo.Userid, systemId)
		// 点赞
		//specialDetailVo.LikeFlag = specialUserLikeMapper.CountSpecialUserLike(userId, specialId, systemId)
		// 收藏
		specialDetailVo.FavFlag = specialUserFavMapper.CountSpecialUserFav(userId, specialId, systemId)
		// 判断用户是否购买资源
		specialDetailVo.BuyFlag, _ = service.ValidatorUserSpecial(&specialDetailVo, userId, specialId, systemId)
		// 购买人数
		specialDetailVo.BuyNum = userBuySpecialMapper.CountUserBuySpecialNo(userId, specialId, systemId)
		if specialDetailVo.BuyFlag > 0 {
			// 如果网盘密码不为空就要进行加密
			if len(panPwd) > 0 {
				specialDetailVo.PanPwd = panPwd
			}
		}
	}
	// 章绑定节
	return &specialDetailVo, err
}

/**
 * @author feige
 * @date 2023-10-08
 * @desc 根据id查询资源信息的业务蹭
 */
func (service *SpecialService) ValiatorBuyFlagIdNo(specialId uint64, userId uint64, systemId uint64) bool {
	// 1: 根据id查询数据层
	special, err := specialMapper.GetById(specialId, systemId)
	if err != nil {
		return false
	}
	specialDetailVo := vo.SpecialDetailVo{}
	utils.CopyProperties(&specialDetailVo, special)
	// 判断用户是否购买资源
	specialDetailVo.BuyFlag, _ = service.ValidatorUserSpecial(&specialDetailVo, userId, specialId, systemId)
	// 是否购买
	return specialDetailVo.BuyFlag > 0
}

func (service *SpecialService) FindSpecialStudents(specialId uint64, systemId uint64) []vo.UserBuySpecialStudentVo {
	userBuyStudents, _ := specialBuyMapper.FindSpecialUserBuyStudents(specialId, systemId)
	var studentsVos []vo.UserBuySpecialStudentVo
	for _, userBuyStudent := range userBuyStudents {
		var studentsVo vo.UserBuySpecialStudentVo
		utils.CopyProperties(&studentsVo, userBuyStudent)
		studentsVos = append(studentsVos, studentsVo)
	}
	return studentsVos

}

/**
 * @author feige
 * @date 2023-10-16
 * @version 1.0
 * @desc 资源用户收藏
 */
func (service *SpecialService) FavSpecialByUserId(userId uint64, specialId uint64, systemId uint64) (bool, error) {
	// 1: 获取redis的rdb对象,目标： sadd ksd:special:1 1
	cacheKey := fmt.Sprintf("COURSE:FAV:%d:%d", specialId, systemId)
	// 2: 完成redis收藏功能
	err := rdb.RdbSAdd(cacheKey, fmt.Sprintf("%d", userId))
	if err != nil {
		return false, err
	}
	// 3: 预留把资源的收藏数量+1
	return true, nil
}

/**
 * @author feige
 * @date 2023-10-16
 * @version 1.0
 * @desc 资源用户取消收藏
 */
func (service *SpecialService) UnFavSpecialByUserId(userId uint64, specialId uint64, systemId uint64) (bool, error) {
	// 1: 获取redis的rdb对象,目标： sadd ksd:special:1 1
	cacheKey := fmt.Sprintf("COURSE:FAV:%d:%d", specialId, systemId)
	// 2: 完成redis收藏功能
	_, err := rdb.RdbSREM(cacheKey, fmt.Sprintf("%d", userId))
	if err != nil {
		return false, err
	}
	// 3: 预留把资源的收藏数量+1
	return true, nil
}

/**
* @author feige
* @date 2023-10-16
* @version 1.0
* @desc 点赞
 */
func (service *SpecialService) LikeSpecial(userId uint64, specialId uint64, systemId uint64) (bool, error) {
	// 1: 获取rdb对象
	cacheKey := fmt.Sprintf("COURSE:LIKE:%d:%d", specialId, systemId)
	// 2:添加广告
	err := rdb.RdbSAdd(cacheKey, fmt.Sprintf("%d", userId))
	if err != nil {
		return false, err
	}
	return true, nil
}

/**
* @author feige
* @date 2023-10-16
* @version 1.0
* @desc 点赞
 */
func (service *SpecialService) UnLikeSpecial(userId uint64, specialId uint64, systemId uint64) (bool, error) {
	// 1: 获取rdb对象
	cacheKey := fmt.Sprintf("COURSE:LIKE:%d:%d", specialId, systemId)
	// 2:添加广告
	_, err := rdb.RdbSREM(cacheKey, fmt.Sprintf("%d", userId))
	if err != nil {
		return false, err
	}
	return true, nil
}

/*
* @desc 更新浏览数
* @author feige
* @date 2023-11-14
* @version 1.0
 */
func (service *SpecialService) UpdateViewCount(opid uint64, ip string, systemId uint64) bool {
	if service.CheckLimitViewCount(opid, ip, systemId) {
		return specialMapper.UpdateViewCount(opid, systemId)
	}
	return true
}

/**
 * 评论的频率检查
 * @author feige
 * @date 2023-11-21
 * @version 1.0
 * @desc
 */
func (service *SpecialService) CheckLimitViewCount(opid uint64, ip string, systemId uint64) bool {
	// 时间频率限制 commentIntervalSeconds == -1不限制，否则就会限制
	// 5代表用户在5秒之内只能评论一次，如果超过在5秒之内提交N次就不停的提示：操作繁忙
	commentIntervalSeconds := beego.AppConfig.DefaultInt("special:viewcount.limit.seconds", 3)
	if commentIntervalSeconds > 0 {
		result := service.GetCommentInterval(opid, ip, systemId, commentIntervalSeconds)
		if !result {
			return false
		}
	}

	return true
}

/**
 * 这里就是setnxex的代码
 * @author feige
 * @date 2023-11-21
 * @version 1.0
 * @desc
 */
func (service *SpecialService) GetCommentInterval(opid uint64, ip string, systemId uint64, intervalTime int) bool {
	key := fmt.Sprintf("special:viewcount:interval:%s:%s:%d", opid, ip, systemId)
	result := rdb.RdbSetEXNX(key, opid, intervalTime)
	return result
}

/**
 * @desc 保存用户的文章浏览记录
 * @author feige
 * @date 2023-11-14
 * @version 1.0
 */
func (service *SpecialService) SaveUserSpecialHits(specialUserHitsContext *context.SpecialUserHitsContext) bool {
	// 接受传递过来的参数
	var specialUserHits model.SpecialUserHits
	utils.CopyProperties(&specialUserHits, specialUserHitsContext)
	// 保存入库
	flag := specialMapper.SaveUserSpecialHits(&specialUserHits)
	return flag
}

/**
 * @author feige
 * @date 2023-10-13
 * @version 1.0
 * @desc 查询资源列表信息，栏目和搜索使用
 */
func (service SpecialService) FindSpecialListAndPage(ctx context.SpecialSearchContext) *page.Page {
	p := specialMapper.FindSpecialListAndPage(ctx)
	specials := p.Records.([]model.Special)
	specialVos := []vo.SpecialVo{}
	for _, special := range specials {
		// 3: 查询当前登录的用户信息和资源id去查询用户资源收藏表
		specialVo := vo.SpecialVo{}
		utils.CopyProperties(&specialVo, special)
		// 2: 如果没有错误就必须把model数据导入vo数据中
		specialVos = append(specialVos, specialVo)
	}
	p.Records = specialVos
	return p
}

/**
 * 验证用户是否购买小册
 * @author feige
 * @date 2023-12-13
 * @version 1.0
 * @desc
 */
func (service *SpecialService) ValidatorUserSpecial(specialDetailvo *vo.SpecialDetailVo, userId uint64, specialId uint64, systemId uint64) (int, error) {
	special, _ := specialMapper.GetById(specialId, systemId)
	if specialDetailvo != nil {
		specialDetailvo.Viewcount = special.Viewcount
		specialDetailvo.FavNum = special.FavNum
		specialDetailvo.Stimer = special.Stimer
	}
	// 1: 如果小册是免费的，直接通过
	if special.PayFlag <= 1 {
		return 1, nil
	}
	// 如果是本身也可以查看
	if special.Userid == userId {
		return 1, nil
	}
	// 2: 查看是不是超级会员或者管理员，直接通过
	user := userMapper.GetUserByID(userId, systemId)
	if user.Role == "admin" || user.VipFlag == 7 {
		return 1, nil
	}

	// 3: 查看小册是否购买,购买通过
	countUserBuySpecialNo := userBuySpecialMapper.CountUserBuySpecialNo(userId, specialId, systemId)
	if countUserBuySpecialNo > 0 {
		return 1, nil
	}

	return 0, errors.New("你尚未订阅资源，无法学习！")
}

/**
 * @author feige
 * @date 2023-10-13
 * @version 1.0
 * @desc 查询专题列表信息，栏目和搜索使用
 */
func (service SpecialService) FindPushSpecialListAndPage(ctx context.SpecialSearchContext) *page.Page {
	cacheKey := fmt.Sprintf("SYSTEM:SPECIAL:FindPushNoteListAndPage:%d", ctx.SystemId)
	jsonString, _ := rdb.RdbGet(cacheKey)
	specialVos := []vo.SpecialVo{}
	tools.JsontoStruct(jsonString, &specialVos)
	if len(specialVos) == 0 {
		p := specialMapper.FindPushSpecialListAndPage(ctx.PageNo, ctx.PageSize, ctx.CategoryCid, ctx.SystemId)
		specials := p.Records.([]model.Special)
		for _, special := range specials {
			// 3: 查询当前登录的用户信息和专题id去查询用户专题收藏表
			specialVo := vo.SpecialVo{}
			utils.CopyProperties(&specialVo, special)
			// 2: 如果没有错误就必须把model数据导入vo数据中
			specialVos = append(specialVos, specialVo)
		}

		p.Records = specialVos
		return p
	} else {
		p := page.Page{}
		p.Records = specialVos
		return &p
	}
}
